package network.TCP;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

import model.data.Audio;
import model.data.FileDescription;

/**
 * Project ChatSystemG6 - INSA 4INFOA1 - 2013/2014
 * <P>
 * <li>TCPServer is the server for the transmission of a file</li>
 * 
 * @author Christelle SIAGO HAPPI
 * 
 */

public class TCPServer implements Runnable {

	/**
	 * the socket of the server
	 */
	private ServerSocket serverSocket;

	/**
	 * the TCP socket
	 */
	private Socket socket;

	/**
	 * read the stream socket
	 */
	private BufferedReader input;
	/**
	 * write the stream socket
	 */
	private PrintWriter output;

	/**
	 * a port number
	 */
	private int port;

	/**
	 * the file description to receive
	 */
	private FileDescription fileToReceived;

	/**
	 * the size of the file to receive
	 */
	private long sizeFileToReceived;

	/**
	 * the default directory where the file will be save
	 */
	private static File defaultDirectory;

	/**
	 * the progress bar describing the speed of the file transmission
	 */
	private ProgressBar progressBar;

	/**
	 * 
	 * @param port
	 *            : the reception port number of the server
	 * @param file
	 *            : the file to send to the remote
	 * @param size
	 *            : the size of the file to send
	 */
	public TCPServer(short port, FileDescription file, long size) {

		this.setPort(port);
		this.setFile(file);
		this.sizeFileToReceived = size;
		this.setDefaultDirectory();
		progressBar = new ProgressBar(size, 'r');
		System.out.println("star the server ...\n");

		try {
			// Step 1: Creation of the socket
			openServer();
		} catch (IOException ex) {
			Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null,
					ex);
		}

	}

	/**
	 * assign a port number
	 * 
	 * @param port
	 */
	public final void setPort(short port) {
		if (port > 1024)
			this.port = port;
	}

	/**
	 * assign the file description to receive
	 * 
	 * @param file
	 */
	public final void setFile(FileDescription file) {
		this.fileToReceived = new FileDescription(file);
	}

	/**
	 * verify if the remote has choosen a directory where to save the file sent
	 * 
	 * @return
	 */
	private boolean setDefaultDirectory() {
		defaultDirectory = new File("../ChatDownload");
		return defaultDirectory.mkdir();
	}

	/**
	 * assign the default directory where the file sent will be saved
	 * 
	 * @param defaultPath
	 */
	public static void setDefaultDirectory(String defaultPath) {
		defaultDirectory = new File(defaultPath);
		defaultDirectory.mkdir();
	}

	/**
	 * launch the server
	 */
	public void startServer() {

		System.out.println("Waiting for server connection\n");
		// Step 2 : waiting for a connexion
		waitConnect();
		System.out.println("successfully connected to the server port  : "
				+ socket);

		// Step 3 : Recovery flow connection
		openFlux();
		try {
			// Step 4 : Handle the connection .
			receptionData();
		} catch (IOException ex) {
			Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null,
					ex);
		}
		// Step 5 : close flow
		closeFlux();

	}

	/**
	 * create the server socket
	 * 
	 * @throws IOException
	 */
	private void openServer() throws IOException {
		try {
			// Creation of the server socket
			serverSocket = new ServerSocket(port);
		} catch (java.io.IOException ex) {
			Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null,
					ex);
			serverSocket.close();
		}

	}

	/**
	 * Waiting for connection
	 */
	private void waitConnect() {
		try {
			// recovery of the socket
			socket = serverSocket.accept();
		} catch (java.io.IOException ex) {
			try {
				Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE,
						null, ex);
				socket.close();
			} catch (IOException ex1) {
				Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE,
						null, ex1);
			}
		}
	}

	/**
	 * Open input stream and output
	 */
	private void openFlux() {
		try {
			// Recovery flow
			input = new BufferedReader(new InputStreamReader(
					socket.getInputStream()));
			output = new PrintWriter(new FileWriter(new File(defaultDirectory
					+ "/" + fileToReceived.getName())), true);

		} catch (java.io.IOException ex) {
			try {
				Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE,
						null, ex);
				input.close();
				output.close();
			} catch (IOException ex1) {
				Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE,
						null, ex1);
			}
		}
	}

	/**
	 * Reception of data
	 * 
	 * @throws IOException
	 */
	private void receptionData() throws IOException {

		int size = (int) sizeFileToReceived;
		Speed TransferSpeed = new Speed();

		int octectRead = 0;
		int TraityOctect = 0;
		char[] receivedData;
		System.out.println("Start of transmission");
		boolean transfer = true;

		long timeDebut = new Date().getTime();
		// As long as you do not get the whole file
		while (transfer) {
			receivedData = new char[size]; // Creating a new table
			octectRead = input.read(receivedData, 0, size);
			if (octectRead > 0) // If you read data
			{
				output.write(receivedData);
				output.flush();
			}
			TraityOctect = TraityOctect + octectRead;
			// Calculate the transfer speed
			TransferSpeed.getSpeed(timeDebut, TraityOctect);
			progressBar.setProgressBar(TransferSpeed);
			if (TraityOctect == size) {
				transfer = false;
				System.out.println("End of the transmission");
				progressBar.setStatus("File saved in              "
						+ defaultDirectory + "\\" + fileToReceived.getName());
				Audio a = new Audio("transfert.wav");
			}
		}
	}

	/**
	 * Close Flow
	 */
	private void closeFlux() {
		try {
			if (input != null)
				input.close(); // close inplut flow
			if (output != null)
				output.close(); // close output flow
			if (socket != null)
				socket.close(); // close the socket
			if (serverSocket != null)
				serverSocket.close(); // close the server
		} catch (java.io.IOException ex) {
			Logger.getLogger(TCPServer.class.getName()).log(Level.SEVERE, null,
					ex);
		}
		System.out.println("Closing stream server");
	}

	@Override
	public void run() {
		startServer();

	}
}
